/*
Copyright 2011 Raymond Giorgi

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
 */

package edu.pitt.cs3530.misc;

import java.util.ArrayList;
import java.util.Iterator;

/**
 * This function is a queue that only stores a certain ('size') number of
 * entries Initially, this was designed to store a history of CPU frequencies
 * for each processor, but now that we're switching to 'C', it probably won't
 * get used (possibly move this to com.distributedray.util)
 * 
 * @author NoOne
 * 
 * @param <T>
 */
public class SizedQueue<T> implements Iterable<T> {
	/**
	 * The iterator class for Sized Queue. Note: this class has a private
	 * constructor because no outside class should be able to call the Iterator
	 * without already having a queue to iterate over
	 * 
	 * @author NoOne
	 * 
	 * @param <T>
	 */
	public class SizedQueueIterator<T> implements Iterator<T> {
		private SizedQueue<T> sizedQueue;
		private int index;
		private int size;

		/**
		 * Because of the local scope of the the Parent class, we need the size
		 * of the queue to be passed in so that the 'hasNext()' function works
		 * correctly.
		 * 
		 * @param parent
		 * @param size
		 */
		private SizedQueueIterator(SizedQueue<T> parent, int size) {
			this.sizedQueue = parent;
			index = -1;
			this.size = size;
		}

		/**
		 * Since the iterator class is only constructed once, we need to
		 * reinitialize certain variables so it performs correctly if called
		 * more than once
		 * 
		 * @return this iterator
		 */
		public SizedQueueIterator<T> initialize() {
			this.index = -1;
			return this;
		}

		/**
		 * 
		 * @return True if the iterator has not reached the end of the queue
		 */
		@Override
		public boolean hasNext() {
			if (index < size) {
				return true;
			}
			return false;
		}

		/**
		 * @return the next element in the list (in relation to the last item
		 *         returned by the iterator).
		 */
		@Override
		public T next() {
			if (hasNext()) {
				index++;
				return sizedQueue.getElement(index);
			}
			return null;
		}

		/**
		 * Delete the entry the iterator is currently on
		 */
		@Override
		public void remove() {
			sizedQueue.remove(index);
			index--;
		}

	}

	private ArrayList<T> queue;
	private int size;
	private int index;
	private SizedQueueIterator<T> iterator;

	/**
	 * Size is the number of elements to be stored in the queue
	 * 
	 * @param size
	 */
	public SizedQueue(int size) {
		this.size = size;
		queue = new ArrayList<T>();
		index = -1;
	}

	public SizedQueue(SizedQueue<T> collection) {
		this.size = collection.getSize();
		index = -1;
		for (T t : collection) {
			this.add(t);
		}
	}

	/**
	 * Add an object
	 * 
	 * @param t
	 */
	public void add(T t) {
		queue.add(t);
		if (queue.size() >= size) {
			queue.remove(0);
		}
	}

	/**
	 * 
	 * @return the number of elements in the list
	 */
	public int getSize() {
		return size;
	}

	/**
	 * 
	 * @param i
	 * @return the object at index 'i'
	 */
	public T getElement(int i) {
		if (i >= 0 && i < queue.size()) {
			return queue.get(i);
		}
		return null;
	}

	/**
	 * Remove an element at the 'index' place within in the queue. Also return
	 * it (useful when we want to use an element one last time. Follows from
	 * Java util data structures)
	 * 
	 * @param index
	 * @return the item that was at index 'index'
	 */
	public T remove(int index) {
		if (indexExists(index)) {
			return queue.remove(index);
		}
		return null;
	}

	/**
	 * 
	 * @param index
	 * @return true if there is a function at place 'index'
	 */
	public boolean indexExists(int index) {
		if (index >= 0 && index < size) {
			return true;
		}
		return false;
	}

	/**
	 * @return an iterator for the queue
	 */
	@Override
	public Iterator<T> iterator() {
		if (iterator == null) {
			iterator = new SizedQueueIterator<T>(this, size);
		}
		return iterator.initialize();
	}
}
